package principal;

import java.awt.*;
import java.awt.event.*;
import java.awt.geom.AffineTransform;

import javax.swing.*;
import java.io.*;
import java.util.ArrayList;
import java.util.Random;
import java.awt.image.*;

import javax.imageio.ImageIO;

import obstaculos.*;

public class Principal extends JPanel implements Runnable{
	public static final int LARGURA_DA_TELA = 480;
	public static final int ALTURA_DA_TELA = 256;
	public static Principal instancia = null;
	
	private Thread animator;
	private boolean running = false;
	private boolean gameOver = false;
	
	private BufferedImage dbImage;
	public Graphics2D dbg;
	
	int FPS,SFPS;
	int fpscount;
	
	Random rnd = new Random();
	
	BufferedImage tileSet, imagemfundo, imagemtelainicial, tileSetDono,
					imagemtelagameover, imagemtelacontroles, imagemtelabriefing,
					imagemtelapausa, imagemtelaparabens;
	BufferedImage spriteParado, spriteAndando;
	BufferedImage spriteDono, spriteDonoDerrotado;
	BufferedImage spriteVida;
	BufferedImage spriteCheckpoint;
	
	boolean LEFT, RIGHT,UP,DOWN,FIRE;
	boolean liberaPulo = true;
	
	int MouseX,MouseY;
	
	boolean mousePressionado = false;
	
	public Personagem heroi;
	public Dono dono;
	public TileMap mapa;
	public TileMapDono tileMapDono, tileMapDono2;
	Tela telaDeEntrada, telaDeGameOver, telaDeSelecao,
			telaDeControles, telaDePausa, telaDeBriefing, telaDeParabens;
	FileInputStream arquivo;
	public Vida vida;
	public int niveisConcluidos = 0;
	
	int telaAtual = 0;//0: Splash
					  //1: Game
					  //2: Briefing
					  //3: Game over
					  //4: Congratulations
					  //5: Controls
					  //6: Pausa
	
	Som somPulo, somDano, somVida;
	
//	public boolean jaMandouPular = false;
	public boolean jaMandouApertar = false;

	public ArrayList<Obstaculo> listaDeObstaculos = new ArrayList<Obstaculo>();
	public ArrayList<Obstaculo> listaDeObstaculos2 = new ArrayList<Obstaculo>();
	public ArrayList<Vida> listaDeVidas = new ArrayList<Vida>();
	public ArrayList<BufferedImage> listaDeSprites = new ArrayList<BufferedImage>();
	public ArrayList<Checkpoint> listaDeCheckpoints = new ArrayList<Checkpoint>();
	public ArrayList<Som> listaDeSons = new ArrayList<Som>();
	
	int timerBriefing = 0;
	
	public Principal()
	{
		instancia = this;
	
		setBackground(Color.white);
		setPreferredSize( new Dimension(LARGURA_DA_TELA - 10, ALTURA_DA_TELA - 10));
	
		// create game components
		setFocusable(true);
	
		requestFocus(); // JPanel now receives key events
	
		if (dbImage == null){
			dbImage = new BufferedImage(LARGURA_DA_TELA, ALTURA_DA_TELA,BufferedImage.TYPE_INT_ARGB);
			if (dbImage == null) {
				System.out.println("dbImage is null");
				return;
			}else{
				dbg = (Graphics2D)dbImage.getGraphics();
			}
		}	

		
		
		addKeyListener( new KeyAdapter() {
			public void keyPressed(KeyEvent e)
				{ 
					int keyCode = e.getKeyCode();
					if(keyCode == KeyEvent.VK_LEFT){
						LEFT = true;
					}
					if(keyCode == KeyEvent.VK_RIGHT){
						RIGHT = true;
					}
					if(keyCode == KeyEvent.VK_SPACE&&liberaPulo==true){
						UP = true;
						liberaPulo = false;
					}
					if(keyCode == KeyEvent.VK_ENTER){
						if(telaAtual == 1){
							telaAtual = 6;
						}else{
							telaAtual = 1;
						}
					}
				}
			@Override
				public void keyReleased(KeyEvent e ) {
					int keyCode = e.getKeyCode();
					if(keyCode == KeyEvent.VK_LEFT){
						LEFT = false;
					}
					if(keyCode == KeyEvent.VK_RIGHT){
						RIGHT = false;
					}
					if(keyCode == KeyEvent.VK_SPACE){
//						jaMandouPular = false;
						UP = false;
						liberaPulo = true;
					}
				}
		});
		addMouseMotionListener(new MouseMotionListener() {
			@Override
			public void mouseMoved(MouseEvent e) {
				MouseX = e.getX();
				MouseY = e.getY();
			}
			@Override
			public void mouseDragged(MouseEvent e) {
				MouseX = e.getX();
				MouseY = e.getY();
			}
		});
		addMouseListener(new MouseListener() {
			@Override
			public void mouseReleased(MouseEvent e) {
				if(telaAtual == 0){
					if(MouseX >= 142 && MouseY >= 157 && MouseX <= 332 && MouseY <= 185){
						telaAtual = 2;
						FIRE = false;
						jaMandouApertar = false;
					}
					if(MouseX >= 142 && MouseY >= 190 && MouseX <= 332 && MouseY <= 217){
						telaAtual = 5;
						FIRE = false;
						jaMandouApertar = false;
					}
					if(MouseX >= 142 && MouseY >= 221 && MouseX <= 332 && MouseY <= 249){
						stopGame();
					}
				}
				if(telaAtual == 1){
					FIRE = false;
					jaMandouApertar = false;
				}
				if(telaAtual == 3){//game over
					if(MouseX >= 42 && MouseY >= 200 && MouseX <= 232 && MouseY <= 228){
						if(niveisConcluidos == 0){
							if(listaDeCheckpoints.get(0).vivo){
								dono.X = 64; dono.Y = 0;
								heroi.X = 64; heroi.Y = 160;
							}else{
								dono.X = 1056 - 64; dono.Y = 32;
								dono.velx = 50;
								heroi.X = 1056; heroi.Y = 160;
							}
							for(int i = 0; i < listaDeObstaculos.size(); i++){
								listaDeObstaculos.get(i).ativado = false;
							}
						}else{
							dono.X = 64; dono.Y = 0;
							heroi.X = 64; heroi.Y = 160;
							for(int i = 0; i < listaDeObstaculos2.size(); i++){
								listaDeObstaculos2.get(i).ativado = false;
							}
						}
						for(int i = 0; i < listaDeVidas.size(); i++){
							listaDeVidas.get(i).vivo = true;
						}
						heroi.direcao = 1;
						dono.direcao = 1;
						dono.velx = 50;
						dono.jaEscolheuPlataforma = false;
						dono.invulneravel = false;
						heroi.vida = 5;
						telaAtual = 1;
						FIRE = false;
						jaMandouApertar = false;
					}
					if(MouseX >= 240 && MouseY >= 200 && MouseX <= 430 && MouseY <= 228){
						timerBriefing = 0;
						telaAtual = 0;
						FIRE = false;
						jaMandouApertar = false;
					}
				}
				if(telaAtual == 4){
					niveisConcluidos++;
					if(MouseX >= 42 && MouseY >= 200 && MouseX <= 232 && MouseY <= 228){
						dono.mapaT = tileMapDono2;
						heroi.listaDeObstaculos = listaDeObstaculos2;
						dono.listaDeObstaculos = listaDeObstaculos2;
						dono.X = 64; dono.Y = 0;
						heroi.X = 64; heroi.Y = 160;
						for(int i = 0; i < listaDeVidas.size(); i++){
							listaDeVidas.get(i).vivo = true;
						}
						heroi.direcao = 1;
						dono.direcao = 1;
						dono.velx = 50;
						dono.jaEscolheuPlataforma = false;
						dono.invulneravel = false;
						heroi.vida = 5;
						telaAtual = 1;
						FIRE = false;
						jaMandouApertar = false;
					}
					if(MouseX >= 240 && MouseY >= 200 && MouseX <= 430 && MouseY <= 228){
						timerBriefing = 0;
						telaAtual = 0;
						FIRE = false;
						jaMandouApertar = false;
					}
				}
				if(telaAtual == 5){
					if(MouseX >= 143 && MouseY >= 202 && MouseX <= 333 && MouseY <= 231){
						telaAtual = 0;
						FIRE = false;
						jaMandouApertar = false;
					}
				}
				if(telaAtual == 6){//pausa
					if(MouseX >= 42 && MouseY >= 200 && MouseX <= 232 && MouseY <= 228){
						telaAtual = 1;
						FIRE = false;
						jaMandouApertar = false;
					}
					if(MouseX >= 240 && MouseY >= 200 && MouseX <= 430 && MouseY <= 228){
						timerBriefing = 0;
						telaAtual = 0;
						FIRE = false;
						jaMandouApertar = false;
					}
				}
			}
			@Override
			public void mousePressed(MouseEvent e) {
				if(jaMandouApertar == false){
					jaMandouApertar = true;
					if(telaAtual == 1 && FIRE == false){
						FIRE = true;
					}
				}else{
					FIRE = false;
				}
				
			}
			@Override
			public void mouseExited(MouseEvent e) {
			}
			@Override
			public void mouseEntered(MouseEvent e) {
			}
			@Override
			public void mouseClicked(MouseEvent e) {
			}
		});
		
		imagemtelainicial = carregaImagem("res/TelaInicial.bmp");
		imagemtelagameover = carregaImagem("res/TelaDeGameOver.bmp");
		imagemtelacontroles = carregaImagem("res/TelaDeControles.bmp");
		imagemfundo = carregaImagem("res/CenarioPrincipal.bmp");
		imagemtelabriefing = carregaImagem("res/TelaDeBriefing.bmp");
		imagemtelapausa = carregaImagem("res/TelaDePausa.bmp");
		imagemtelaparabens = carregaImagem("res/TelaDeParabens.bmp");
		
		tileSet = carregaImagem("res/Fase 1.png");
		tileSetDono = carregaImagem("res/Fase1_Velhinho.png");
		spriteAndando = carregaImagem("res/Jogador_andando.png");
		spriteParado = carregaImagem("res/64X64.png");
		spriteDono = carregaImagem("res/Dono.png");
		spriteDonoDerrotado = carregaImagem("res/Dono_derrotado.png");
		spriteVida = carregaImagem("res/16X16_2.png");
		spriteCheckpoint = carregaImagem("res/Checkpoint.png");

		telaDeEntrada = new Tela(imagemtelainicial);
		telaDeGameOver = new Tela(imagemtelagameover);
		telaDeControles = new Tela(imagemtelacontroles);
		telaDePausa = new Tela(imagemtelapausa);
		telaDeBriefing = new Tela(imagemtelabriefing);
		telaDeParabens = new Tela(imagemtelaparabens);
		mapa = new TileMap(tileSet, 15, 8, 89, 8);
		tileMapDono = new TileMapDono(tileSetDono, 15, 8, 89, 8);
		tileMapDono2 = new TileMapDono(tileSetDono, 15, 8, 89, 8);
		
		somPulo = new Som("Pulo.au");
		somDano = new Som("Dano.au");
		somVida = new Som("Vida.au");
		
		MouseX = MouseY = 0;
		
		vida = new Vida(1664, 96, spriteVida);
		listaDeVidas.add(vida);

		listaDeCheckpoints.add(new Checkpoint(1056, 160, spriteCheckpoint));
		
		carregaSprites("res/Sprites.csv");
		carregaObstaculos("res/Obstaculos.csv", listaDeObstaculos);
		carregaObstaculos("res/Obstaculos2.csv", listaDeObstaculos2);
		carregaSons("res/Sons.csv", listaDeSons);
		heroi = new Personagem(0,160,spriteAndando,0);
		dono = new Dono(spriteDono,0,0);
		
		carregaTileMap("res/nivel1.csv", mapa.mapa);
		carregaTileMap("res/nivel1_colisoes.csv", mapa.mapaDeColisao);
		carregaTileMap("res/nivel1_dono.csv", tileMapDono.mapa);
		carregaTileMap("res/nivel1_colisoes_dono.csv", tileMapDono.mapaDeColisao);
		carregaTileMap("res/nivel2_dono.csv", tileMapDono2.mapa);
		carregaTileMap("res/nivel2_colisoes_dono.csv", tileMapDono2.mapaDeColisao);
	
	} // end of GamePanel()

	public void addNotify(){
		super.addNotify();
		startGame();
	}

	private void startGame(){
		if (animator == null || !running) {
			animator = new Thread(this);
			animator.start();
		}
	}

	public void stopGame(){
		running = false;
	}

	public void run(){
		running = true;
		
		long DifTime,TempoAnterior;
		
		int segundo = 0;
		DifTime = 0;
		TempoAnterior = System.currentTimeMillis();
		
		while(running) {
		
			gameUpdate(DifTime); // game state is updated
			gameRender(); // render to a buffer
			paintImmediately(0, 0, 480, 256); // paint with the buffer
		
			try {
				Thread.sleep(0); // sleep a bit
			}catch(InterruptedException ex){
			}
			
			DifTime = System.currentTimeMillis() - TempoAnterior;
			TempoAnterior = System.currentTimeMillis();
			
			if(segundo!=((int)(TempoAnterior/1000))){
				FPS = SFPS;
				SFPS = 1;
				segundo = ((int)(TempoAnterior/1000));
			}else{
				SFPS++;
			}
		}
		System.exit(0); // so enclosing JFrame/JApplet exits
	} // end of run()

	int timerfps = 0;

	private void gameUpdate(long DiffTime)
	{
		if(telaAtual == 1){
			heroi.UP = UP; heroi.LEFT = LEFT; heroi.RIGHT = RIGHT; heroi.FIRE = FIRE;
			heroi.SimulaSe(DiffTime);
			if(niveisConcluidos == 0){
				for(int i = 0; i < listaDeObstaculos.size(); i++){
					listaDeObstaculos.get(i).SimulaSe(DiffTime);
				}
			}else{
				for(int i = 0; i < listaDeObstaculos2.size(); i++){
					listaDeObstaculos2.get(i).SimulaSe(DiffTime);
				}
			}
			dono.SimulaSe(DiffTime);
			mapa.Posiciona((int)heroi.X-(LARGURA_DA_TELA/2),(int)heroi.Y-(ALTURA_DA_TELA/2));
			if(niveisConcluidos == 0){
				tileMapDono.Posiciona((int)heroi.X-(LARGURA_DA_TELA/2),(int)heroi.Y-(ALTURA_DA_TELA/2));
			}else{
				tileMapDono2.Posiciona((int)heroi.X-(LARGURA_DA_TELA/2),(int)heroi.Y-(ALTURA_DA_TELA/2));
			}
		}
	}

	private void gameRender(){
		dbg.setColor(Color.BLACK);
		if(telaAtual == 0){//splash
			telaDeEntrada.DesenhaSe(dbg);
		}else if (telaAtual == 1){//gameplay
			mapa.DesenhaSe(dbg);
			if(niveisConcluidos == 0){
				tileMapDono.DesenhaSe(dbg);
			}else{
				tileMapDono2.DesenhaSe(dbg);
			}
			heroi.DesenhaSe(dbg,mapa.MapX,mapa.MapY);
			dono.DesenhaSe(dbg,mapa.MapX,mapa.MapY);
			if(niveisConcluidos == 0){
				for(int i = 0; i < listaDeObstaculos.size(); i++){
					listaDeObstaculos.get(i).DesenhaSe(dbg,mapa.MapX,mapa.MapY);
				}
			}else{
				for(int i = 0; i < listaDeObstaculos2.size(); i++){
					listaDeObstaculos2.get(i).DesenhaSe(dbg,mapa.MapX,mapa.MapY);
				}
			}
			for(int i = 0; i < listaDeVidas.size(); i++){
				listaDeVidas.get(i).DesenhaSe(dbg,mapa.MapX,mapa.MapY);
			}
			for(int i = 0; i < listaDeCheckpoints.size(); i++){
				listaDeCheckpoints.get(i).DesenhaSe(dbg,mapa.MapX,mapa.MapY);
			}
			for(int i = 0; i < heroi.vida; i++){
				dbg.drawImage(spriteVida, i*32, 223, ((i+1)*32)-1, 255, 0, 0, 32, 32, null);
			}
		}else if (telaAtual == 2){//briefing
			telaDeBriefing.DesenhaSe(dbg);
			timerBriefing++;
			if(timerBriefing == 1000){
				dono.invulneravel = false;
				dono.X = 64; dono.Y = 0;
				heroi.X = 64; heroi.Y = 160;
				heroi.vida = 5;
				telaAtual = 1;
			}
		}else if (telaAtual == 3){//game over
			telaDeGameOver.DesenhaSe(dbg);
		}else if (telaAtual == 4){//congratulations
			telaDeParabens.DesenhaSe(dbg);
		}else if (telaAtual == 5){//controls
			telaDeControles.DesenhaSe(dbg);
		}else if (telaAtual == 6){//pausa
			telaDePausa.DesenhaSe(dbg);
		}
	}

	public void paintComponent(Graphics g){
		super.paintComponent(g);
		if (dbImage != null)
			g.drawImage(dbImage, 0, 0, null);
	}

	public static void main(String args[]){
		Principal ttPanel = new Principal();
		JFrame app = new JFrame("Jogo");
		app.getContentPane().add(ttPanel, BorderLayout.CENTER);
		app.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		app.pack();
	  	app.setResizable(false);  
	  	app.setVisible(true);
	}

	public BufferedImage carregaImagem(String filename){
		BufferedImage retorno = null;
		try {
			BufferedImage imgtmp = ImageIO.read(new File(filename));
			retorno = new BufferedImage(imgtmp.getWidth(), imgtmp.getHeight(), BufferedImage.TYPE_INT_ARGB);
			retorno.getGraphics().drawImage(imgtmp, 0, 0, null);
			imgtmp=null;
		}
		catch(IOException e) {
			System.out.println("Load Image error: "+filename);
		}
		return retorno;
	}

	public void carregaTileMap(String filename, int tileMap[][]){
		try{
			arquivo = new FileInputStream(filename);
			DataInputStream in = new DataInputStream(arquivo);
			BufferedReader br = new BufferedReader(new InputStreamReader(in));
			String linhaArquivo;
			String[] linha;
			int contadorI = 0;
			while((linhaArquivo = br.readLine()) != null){
				linha= linhaArquivo.split(",");
				for(int j = 0; j < 89; j++){
					tileMap[contadorI][j] = Integer.parseInt(linha[j]);
				}
				contadorI++;
			}
			arquivo.close();
			in.close();
		}catch(IOException e){
		}
	}
	
	public void carregaObstaculos(String filename, ArrayList<Obstaculo> lista){
		try{
			arquivo = new FileInputStream(filename);
			DataInputStream in = new DataInputStream(arquivo);
			BufferedReader br = new BufferedReader(new InputStreamReader(in));
			String linhaArquivo;
			String[] linha;
			while((linhaArquivo = br.readLine()) != null){
				linha= linhaArquivo.split(",");
				int x = Integer.parseInt(linha[1]);
				int y = Integer.parseInt(linha[2]);
				BufferedImage imagem = listaDeSprites.get(Integer.parseInt(linha[3]));
				BufferedImage imagemAtivacao = listaDeSprites.get(Integer.parseInt(linha[4]));
				if(linha[0].equals("Peso")){
					lista.add(new Peso(x,y,imagem,imagemAtivacao));
				}else if(linha[0].equals("Elevador")){
					lista.add(new Elevador(x,y,imagem,imagemAtivacao));
				}else if(linha[0].equals("ElevadoresSortidos")){
					lista.add(new ElevadoresSortidos(x,y,imagem,imagemAtivacao));
				}else if(linha[0].equals("Alcapao")){
					lista.add(new Alcapao(x,y,imagem,imagemAtivacao));
				}else if(linha[0].equals("PlataformasCiclicas")){
					lista.add(new PlataformasCiclicas(x,y,imagem,imagemAtivacao));
				}else if(linha[0].equals("BolaDeFerro")){
					lista.add(new BolaDeFerro(x,y,imagem,imagemAtivacao));
				}else if(linha[0].equals("Balao")){
					lista.add(new Balao(x,y,imagem,imagemAtivacao));
				}else if(linha[0].equals("MudancaDeDirecao")){
					lista.add(new MudancaDeDirecao(x,y,imagem,imagemAtivacao));
				}else if(linha[0].equals("Esteira")){
					lista.add(new Esteira(x,y,imagem,imagemAtivacao));
				}
			}
			arquivo.close();
			in.close();
		}catch(IOException e){
		}
	}
	public void carregaSprites(String filename){
		try{
			arquivo = new FileInputStream(filename);
			DataInputStream in = new DataInputStream(arquivo);
			BufferedReader br = new BufferedReader(new InputStreamReader(in));
			String linhaArquivo;
			while((linhaArquivo = br.readLine()) != null){
				BufferedImage img = null;
				try {
				    img = ImageIO.read(new File("res/" + linhaArquivo));
				} catch (IOException e) {
				}
				//BufferedImage imagemAtivacao = carregaImagem(linha[4]);
				listaDeSprites.add(img);
			}
			arquivo.close();
			in.close();
		}catch(IOException e){
		}
	}

	public void carregaSons(String filename, ArrayList<Som> lista){
		try{
			arquivo = new FileInputStream(filename);
			DataInputStream in = new DataInputStream(arquivo);
			BufferedReader br = new BufferedReader(new InputStreamReader(in));
			String linhaArquivo;
			while((linhaArquivo = br.readLine()) != null){
				Som som = new Som(linhaArquivo);
				lista.add(som);
			}
			arquivo.close();
			in.close();
		}catch(IOException e){
		}
	}
	
}